
import { defineComponent, defineAsyncComponent, resolveComponent, toRaw, nextTick } from 'vue';


let BitmapFonts = defineAsyncComponent(async () => {
    if (!BitmapFonts.hanzi_by_frequency) {
        BitmapFonts.hanzi_by_frequency = (await axios('./components/bitmapFonts/hanzi_by_frequency.json')).data;
    }
    let webCustomFonts = function () {
        var fontFaces = [];
        document.fonts.forEach(font => {
            fontFaces.push(font.family);
        })
        return fontFaces;
    }
    return {
        template: (await axios('./components/bitmapFonts/bitmapFonts.html')).data,
        components: {},
        data() {
            return {
                currentFont: null,
                avaliableFonts: [...webCustomFonts(),
                    'serif', 'monospace', 'sans-serif', 'cursive', 'fantasy', 'script',
                    '等线', '黑体', '宋体', '楷体', '仿宋', '隶书', '幼圆', '华文细黑', '微软雅黑'],
                customFonts: [],
                customChatStr: '',
                colors: [{ r: 0, g: 0, b: 0 }, { r: 255, g: 255, b: 255 }],
                displayChar: '',
                options: null,
                enabled: false,
            }
        },
        watch: {
            customChatStr(v) {
                if (this.currentFont) {
                    this.currentFont.customChars = [...new Set(Array.from(v))].sort();
                }
            },
            currentFont(v) {
                this.customChatStr = v.customChars.join('');
            },
            displayChar() {
                this.redraw();
            },
            'currentFont.font'() {
                this.redraw();
            },
            'currentFont.size'() {
                this.redraw();
            },
            'currentFont.luminance'() {
                this.redraw();
            },
            'currentFont.stroke'() {
                this.redraw();
            },
            enabled(enabled) {
                if (!enabled) {
                    this.save();
                    OB_IDE.removeComponent(this);
                } else {
                    this.load();
                }
            }
        },
        methods: {
            save() {
                let conf = { fonts: toRaw(this.customFonts) };
                VFS.partition.config.put("bitmapFonts.json", conf);
            },
            load() {

                if (VFS.partition.config) {
                    VFS.partition.config.get("bitmapFonts.json", (conf) => {
                        if (!conf) {
                            conf = { fonts: [BitmapFonts.defaultFont()] };
                        }
                        if (conf.fonts.length == 0) {
                            conf.fonts.push(BitmapFonts.defaultFont())
                        }
                        this.customFonts = conf.fonts;
                        this.currentFont = this.customFonts[0];
                        this.customChatStr = this.currentFont.customChars.join('');
                    });
                }
            },
            reload() {
                let t = this.customFonts;
                this.customFonts = null;
                this.customFonts = t;
                t = this.currentFont;
                this.currentFont = null;
                this.currentFont = t;
            },
            redraw() {
                let canvas = this.$refs.bitmapFontsCanvas;
                if (!canvas) {
                    nextTick(this.redraw);
                    return;
                }
                if (this.currentFont) {
                    BitmapFonts.drowOnCanvas(canvas, this.currentFont, this.displayChar, this.options.colors || this.colors);
                }
            },
            showSelectCustomChar() {
                let selectedText = window.getSelection().toString();
                if (selectedText) {
                    this.displayChar = Array.from(selectedText)[0];
                }
            },
            async addFonts() {
                let name = await OB_IDE.asyncPrompt(OB_IDE.$t('请输入字体名称'), 'font');
                if (name) {
                    let o = this.customFonts.find(f => f.name == name);
                    if (!o) {
                        let f = JSON.parse(JSON.stringify(
                            this.currentFont ?
                                toRaw(this.currentFont)
                                : BitmapFonts.defaultFont()));
                        f.id = Math.random().toString(36).substring(2);
                        f.name = name;
                        f.additionalChinese = 'none';
                        this.customFonts.push(f);
                        this.currentFont = f;
                    } else {
                        this.currentFont = o;
                    }
                }
            },
            async rename() {
                if (this.currentFont) {
                    this.currentFont.name = await OB_IDE.asyncPrompt(OpenBlock.i("请输入新名字"), this.currentFont.name);
                    this.reload();
                }
            },
            removeFont() {
                let p = this.customFonts.findIndex(f => f.name == this.currentFont.name);
                if (p >= 0) {
                    this.customFonts.splice(p, 1);
                    this.currentFont = this.customFonts[0] || BitmapFonts.defaultFont();
                }
            }
        }
    }
});
// 创建一个新的style元素  
var style = document.createElement('style');

// 添加样式内容  
style.innerHTML = `
.OB-bitmapFonts-window .ivu-modal-header{
    display: none;
}
#bitmapFontsCanvas{
    width:50%;
    height:auto;
    image-rendering: pixelated;
    border:1px solid gray;
    float:left;
    margin-right:10px;
}
#OB-bitmapFonts-settings{
    float:left;
    width:calc(50% - 10px);
}
#OB-bitmapFonts-chars{
    float:left;
    width:100%;
    max-height:300px;
    overflow-y:auto;
    margin-top:10px;
}
`;

// 将style元素添加到head中  
document.head.appendChild(style);
BitmapFonts.openSettings = async function (options) {
    await OpenBlock.saveAllSrc();
    let win = await OB_IDE.addComponent(BitmapFonts);
    win.options = options;
    win.enabled = true;
};
function groupArray(arr, size) {
    var result = [];
    for (var i = 0; i < arr.length; i += size) {
        result.push(arr.slice(i, i + size));
    }
    return result;
}
BitmapFonts.defaultFont = function () {
    return {
        size: 15, font: 'serif', luminance: 240, name: 'serif', id: Math.random().toString(36).substring(2),
        customChars: [], stroke: false,
        "additionalChinese": "none"
    };
}
BitmapFonts.drowOnCanvas = function (canvas, bitmapFont, displayChar, colors) {
    if (!colors) {
        colors = [{ r: 0, g: 0, b: 0 }, { r: 0, g: 0, b: 255 }]
    }
    let ctx = canvas.getContext('2d', { willReadFrequently: true });
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.textBaseline = 'middle';
    ctx.font = (bitmapFont.size) + 'px  ' + bitmapFont.font;
    if (bitmapFont.stroke) {
        ctx.strokeText(displayChar, 1, bitmapFont.size / 2, bitmapFont.size);
    } else {
        ctx.fillText(displayChar, 1, bitmapFont.size / 2, bitmapFont.size);
    }

    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;
    let points = groupArray(data, 4).map(g => g.reduce((t, v) => t + v, 0));
    points.forEach((v, i, points) => {
        let color;
        if (v < 255 - bitmapFont.luminance) {
            color = colors[0];
        } else {
            color = colors[1];
        }
        let style = '#' + color.r.toString(16).padStart(2, '0') + color.g.toString(16).padStart(2, '0') + color.b.toString(16).padStart(2, '0');
        ctx.fillStyle = style;
        ctx.fillRect(i % canvas.width, Math.floor(i / canvas.width), 1, 1);
    });
};
BitmapFonts.charToBytes = function (c, font) {
    const canvas = new OffscreenCanvas(font.size, font.size);
    BitmapFonts.drowOnCanvas(canvas, font, c, null);
    const offscreenCtx = canvas.getContext('2d', { willReadFrequently: true });
    const imageData = offscreenCtx.getImageData(0, 0, font.size, font.size);
    const data = imageData.data;
    let points = groupArray(data, 4).map(g => g[0] + g[1] + g[2] > 0);
    let bytePoints = groupArray(points, 8).map(g =>
        //(g[15]) << 15 | (g[14]) << 14 | (g[13]) << 13 | (g[12]) << 12 | (g[11]) << 11 | (g[10]) << 10 | (g[9]) << 9 | (g[8] << 8) |
        (g[7]) << 7 | (g[6]) << 6 | (g[5]) << 5 | (g[4]) << 4 | (g[3]) << 3 | (g[2]) << 2 | (g[1]) << 1 | (g[0]));
    return bytePoints;
};
BitmapFonts.char3 = function (i) {
    function toHex(m) {
        return '0x' + ((i >> m) & 0xFF).toString(16);
    }
    return `${toHex(16)},${toHex(8)},${toHex(0)}`;
}
BitmapFonts.toC = async function (scene) {
    if (!BitmapFonts.hanzi_by_frequency) {
        BitmapFonts.hanzi_by_frequency = (await axios('./components/bitmapFonts/hanzi_by_frequency.json')).data;
    }
    let config = await VFS.partition.config.get("bitmapFonts.json");
    let fonts = config?.fonts;
    if (!fonts) {
        fonts=[];
    }
    let srcs = OpenBlock.BlocklyParser.loadedFiles.srcs;
    srcs = srcs.filter(s => scene.srcList.indexOf(s.name) >= 0);
    let requiredString = srcs.map(s => s.__compiled ? Object.keys(s.__compiled.relocation.string).reduce((a, b) => a + b).split('') : []).flat();
    let requiredChat = [...new Set(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        "，","。",".","！","：",":","“","”","￥","%","~","·","……","*","#","@","/","\\","*","-","+","=","&","^","$","—","、","《","》","π","·","【","】","｛","｝","〈","〉","［","］","（","）","(",")","{","}","\"","'",";","；",...requiredString.flat()])];
    let code = [];
    let IdNamePairs = [];
    const encoder = new TextEncoder();
    fonts.forEach((font, i) => {
        let cChars = [];
        let cCharIndex = [];
        // 去除空格，排序后，重新添加到最前
        let allChars = requiredChat.concat(Array.from(font.customChars)).filter(c => c !== ' ');
        allChars = [...new Set(allChars.flat())];
        switch (font.additionalChinese) {
            case '1000':
                allChars = allChars.concat(BitmapFonts.hanzi_by_frequency.slice(0, 1000));
                break;
            case '2000':
                allChars = allChars.concat(BitmapFonts.hanzi_by_frequency.slice(0, 2000));
                break;
            case '3000':
                allChars = allChars.concat(BitmapFonts.hanzi_by_frequency.slice(0, 3000));
                break;
            case '4000':
                allChars = allChars.concat(BitmapFonts.hanzi_by_frequency.slice(0, 4000));
                break;
            case '5000':
                allChars = allChars.concat(BitmapFonts.hanzi_by_frequency.slice(0, 5000));
                break;
            case '6000':
                allChars = allChars.concat(BitmapFonts.hanzi_by_frequency.slice(0, 6000));
                break;
            case 'all':
                allChars = allChars.concat(BitmapFonts.hanzi_by_frequency);
                break;
        }
        allChars.sort();
        allChars.unshift(' ');
        let bytesPerChar = 0;
        let indexLen = 0;
        allChars.map((c, i1) => {
            let b = BitmapFonts.charToBytes(c, font);
            bytesPerChar = b.length;
            // 点阵字体数组
            cChars.push(`/* ${c} */ ` + b.map(v => '0x' + v.toString(16).padStart(4, '0')).join(',') + ',');
            // 调用encode方法将字符串编码为UTF-8格式的Uint8Array
            const utf8EncodedArray = encoder.encode(c);

            // 如果需要将Uint8Array进一步转换为纯数字数组（每个元素代表一个字节）
            const utf8NumbersArray = Array.from(utf8EncodedArray);
            // 点阵索引数组
            // 因为 utf-8 首字节不会出现 0xff，既不会出现 0x00 0xFF 的连续组合。
            // 每一个文字最后用0x00结束，所以索引首字节可用0xFF分割
            // 索引末字节可用0x00分割

            cCharIndex.push('0xFF,' + BitmapFonts.char3(i1) + ` /* ${c} */ ` + ',0,' + utf8NumbersArray.map((v, k) => { return '0x' + v.toString(16) }).join(',') + ',0');
            indexLen += 1 + 3 + 1 + utf8NumbersArray.length + 1;
        });
        code.push(
            `\nstatic const unsigned char cChars_${font.id}[] = {\n` + cChars.join('\n') + `\n};\n` +
            `static const unsigned char cCharIndex_${font.id}[] = {\n` + cCharIndex.join(',\n') + '\n};\n' +
            `BitmapFontDef Font_${font.id} = {${font.size},${font.size},(char*)cChars_${font.id},${bytesPerChar},cCharIndex_${font.id},${indexLen},${cChars.length}};\n`);
        IdNamePairs.push({ id: font.id, name: font.name });
    });
    let c = code.join('\n');
    let idx = IdNamePairs.map((v, i) => {
        return `
    if(strcmp(name, "${v.name}") == 0){
        return Font_${v.id};
    }
    `;
    }).join('\n');
    let search = `
static BitmapFontDef getBitmapFont(char* name){
    ${idx}
    printf("Unknown font %s\\n",name);
    abort();
}
`;
    return c + search;
};
// ${[...new Set(fonts.map((f, i) => { return `uint8_t bitmapFont${i}[${"3" || Math.ceil(f.size * f.size / 8)}];`; }))].join('\n')}
export default BitmapFonts;
BitmapFonts.install = function () {
    class BitmapFontProvider extends OB_NativeBlockArgumentProvider {
        /**
         * 下拉列表的选项
         * @type {Array.<Object.<string,String>>|Function} 国际化->返回值的键值对
         */
        options;
        /**
         * @type {String}
         */
        arg;
        /**
         * @type {String}
         */
        parentBlockType;
        workspace;
        /**
         * 
         * @param {xmldom} blockDom 本地块xml配置中的block节点
         * @param {xmldom} providerCfg 本地块配置中的provider配置
         */
        init(fieldName, blockDom, providerCfg) {
            this.arg = fieldName;
            this.parentBlockType = blockDom.getAttribute('nativeCall');
            this.options = this._options.bind(this);
        }
        /**
         * 
         * @param {Blockly.Workspace} workspace
         * @param {String} checkType 需要的类型
         * @param {String} inputName input名称
         * @param {Blockly.Input} input input对象
         */
        makeBlock(workspace, checkType, inputName, input) {
            if (checkType && checkType !== 'String') {
                throw Error('BitmapFontProvider 只支持 String 类型');
            }
            this.workspace = workspace;
            let blk = workspace.newBlock('empty_provider');
            blk.mutation = JSON.stringify({ parentType: this.parentBlockType, argName: this.arg, checkType: 'String' });
            blk.updateBlock();
            return blk;
        }
        _options() {
            let ret = [];
            if (VFS.partition.config) {
                VFS.partition.config.get("bitmapFonts.json", (conf) => {
                    if (!conf) {
                        return;
                    }
                    conf.fonts.forEach(f => {
                        ret.push([f.name, f.name]);
                    });
                });
            }
            if (ret.length == 0) {
                ret.push(['', '']);
            }
            return ret;
        }
    }
    OpenBlock.registerFieldProvider('BitmapFontProvider', BitmapFontProvider);
};